package pac;

import io.OutputWriter;
import datastructures.WorkUnit;


public class SamplingThread implements Runnable {
	
	private WorkUnit regionToSearch;
	private final SearchDatastructure searcher;
	private int thread_number;
	private OutputWriter outputter;
	
	/*
	 * Constructor
	 */
	public SamplingThread ( WorkUnit searchRegion, SearchDatastructure I, int threadNo, OutputWriter O ) {
		regionToSearch = searchRegion;
		searcher = I;
		thread_number = threadNo;
		outputter = O;
	}

	@Override
	public void run(  ) {
		//1. Stage 1 sampling
		System.out.println("\nStarting thread " + thread_number + ": " + regionToSearch.toStringBrief() ); //( filter=" + k + ", trials=" + regionToSearch.getMaxTrialsRequired() + " )"
		System.out.println("Brute force = " + regionToSearch.getBruteForceCombinationsInRegion() + " tests.");
		System.out.println("Expecting < " + (long) regionToSearch.getWorstExpectedCombinationsFromRegion() + " candidates."); 
		
		WorkHorse stage1sampler = new WorkHorse(regionToSearch, searcher, outputter);
		
		boolean finished = false;
		long stage1TimeSpent = 0;
		long stage2TimeSpent = 0;
		long numberOfStage1Candidates = 0;
		long numberOfTrialsFinished = 0;
		
					
		long timeBeforeStage1 = System.currentTimeMillis();
		int trialsPerformed = stage1sampler.requiredSamples();
		
		finished = stage1sampler.doSampling();
		if(!finished) {
			System.err.println("<Shyte> BROKEN BUILD! \n Thread quit before full scan. </Shyte>");
			System.exit(1);
		}
		
		int candidatesTested = stage1sampler.candidatesTested();
		long timeAfterStage1 = System.currentTimeMillis();

		stage1TimeSpent += (timeAfterStage1 - timeBeforeStage1);
		numberOfTrialsFinished += trialsPerformed;
		numberOfStage1Candidates += candidatesTested;
		
		printPerformance(numberOfStage1Candidates, numberOfTrialsFinished, stage1TimeSpent, stage2TimeSpent);
		
		stage1sampler = null;
	}
	
	
	/*
	 * Output performance of this thread
	 */
	public void printPerformance(long numberOfStage1Candidates, long numberOfTrialsFinished, double stage1TimeSpent, double stage2TimeSpent) 
	{
		double absoluteFactorSavings = (double) regionToSearch.getBruteForceCombinationsInRegion()/numberOfStage1Candidates;
		double amortizedFactorSavings = searcher.userParams.getPower() * absoluteFactorSavings;
		System.out.println("Pruning factor = " + absoluteFactorSavings + " (absolute), " + amortizedFactorSavings + " (amortized)");
		
		//write to file
		//stage2follower.writeStage2Output();
		
		searcher.stage1Candidates += numberOfStage1Candidates;
		searcher.stage1Trials += numberOfTrialsFinished;
		searcher.stage1Time += stage1TimeSpent;
		searcher.stage2Time += stage2TimeSpent;
		
		System.out.println("Time taken by Thread " + thread_number + " = " + stage1TimeSpent/1000 + " seconds.");
//		System.out.println("Time taken by Thread " + thread_number + " Stage2 = " + stage2TimeSpent/1000 + " seconds.");		
		System.out.println("Cummulative time spent so far: " + (System.currentTimeMillis() - searcher.startTimeMs)/1000 + " seconds.");
	}

}
